{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\" role=\"alert\">\n",
    "    This tutorial contains a lot of bokeh plots, which may take a little while to load and render.\n",
    "</div>\n",
    "\n",
    "``Element``s are the basic building blocks for any HoloViews visualization. These are the objects that can be composed together using the various [Container](Containers.ipynb) types. \n",
    "Here in this overview, we show an example of how to build each of these ``Element``s directly out of Python or Numpy data structures.  An even more powerful way to use them is by collecting similar ``Element``s into a HoloMap, as described in [Exploring Data](Exploring_Data.ipynb), so that you can explore, select, slice, and animate them flexibly, but here we focus on having small, self-contained examples.  Complete reference material for each type can be accessed using our [documentation system](Introduction.ipynb#ParamDoc).  This tutorial uses the default matplotlib plotting backend; see the [Bokeh Elements](Bokeh_Elements.ipynb) tutorial for the corresponding bokeh plots.\n",
    "\n",
    " \n",
    "\n",
    "## Element types\n",
    "\n",
    "This class hierarchy shows each of the ``Element`` types.\n",
    "Each type is named for the default or expected way that the underlying data can be visualized.  E.g., if your data is wrapped into a ``Surface`` object, it will display as a 3D surface by default, whereas the same data embedded in an ``Image`` object will display as a 2D raster image.  But please note that the specification and implementation for each ``Element`` type does not actually include *any* such visualization -- the name merely serves as a semantic indication that you ordinarily think of the data as being laid out visually in that way.  The actual plotting is done by a separate plotting subsystem, while the objects themselves focus on storing your data and the metadata needed to describe and use it.  \n",
    "\n",
    "This separation of data and visualization is described in detail in the [Options tutorial](Options.ipynb), which describes all about how to find out the options available for each ``Element`` type and change them if necessary, from either Python or IPython Notebook.  When using this tutorial interactively in an IPython/Jupyter notebook session, we suggest adding ``%output info=True`` after the call to ``notebook_extension`` below, which will pop up a detailed list and explanation of the available options for visualizing each ``Element`` type, after that notebook cell is executed.  Then, to find out all the options for any of these ``Element`` types, just press ``<Shift-Enter>`` on the corresponding cell in the live notebook. \n",
    "\n",
    "The types available:\n",
    "\n",
    "<dl class=\"dl-horizontal\">\n",
    "  <dt><a href=\"#Element\"><code>Element</code></a></dt><dd>The base class of all <code>Elements</code>.</dd>\n",
    "</dl>\n",
    "\n",
    "### <a id='ChartIndex'></a> <a href=\"#Chart Elements\"><code>Charts:</code></a>\n",
    "\n",
    "<dl class=\"dl-horizontal\">\n",
    "  <dt><a href=\"#Curve\"><code>Curve</code></a></dt><dd>A continuous relation between a dependent and an independent variable. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#ErrorBars\"><code>ErrorBars</code></a></dt><dd>A collection of x-/y-coordinates with associated error magnitudes. <font color='green'>&#x2713;</font></dd>\n",
    "    <dt><a href=\"#Spread\"><code>Spread</code></a></dt><dd>Continuous version of ErrorBars. <font color='green'>&#x2713;</font></dd>\n",
    "    <dt><a href=\"#Area\"><code>Area</code></a></dt><dd>Area under the curve or between curves. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Bars\"><code>Bars</code></a></dt><dd>Data collected and binned into categories. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Histogram\"><code>Histogram</code></a></dt><dd>Data collected and binned in a continuous space using specified bin edges. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#BoxWhisker\"><code>BoxWhisker</code></a></dt><dd>Distributions of data varying by 0-N key dimensions.<font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Scatter\"><code>Scatter</code></a></dt><dd>Discontinuous collection of points indexed over a single dimension. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Points\"><code>Points</code></a></dt><dd>Discontinuous collection of points indexed over two dimensions. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#VectorField\"><code>VectorField</code></a></dt><dd>Cyclic variable (and optional auxiliary data) distributed over two-dimensional space. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Spikes\"><code>Spikes</code></a></dt><dd>A collection of horizontal or vertical lines at various locations with fixed height (1D) or variable height (2D). <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#SideHistogram\"><code>SideHistogram</code></a></dt><dd>Histogram binning data contained by some other <code>Element</code>. <font color='green'>&#x2713;</font></dd>\n",
    "  </dl>\n",
    "\n",
    "### <a id='Chart3DIndex'></a> <a href=\"#Chart3D Elements\"><code>Chart3D Elements:</code></a>\n",
    "\n",
    "<dl class=\"dl-horizontal\">\n",
    "  <dt><a href=\"#Surface\"><code>Surface</code></a></dt><dd>Continuous collection of points in a three-dimensional space. <font color='red'>&#x2717;</font></dd>\n",
    "  <dt><a href=\"#Scatter3D\"><code>Scatter3D</code></a></dt><dd>Discontinuous collection of points in a three-dimensional space. <font color='red'>&#x2717;</font></dd>\n",
    "  <dt><a href=\"#Trisurface\"><code>Trisurface</code></a></dt><dd>Continuous but irregular collection of points interpolated into a Surface using Delaunay triangulation. <font color='red'>&#x2717;</font></dd>\n",
    "</dl>\n",
    "\n",
    "\n",
    "### <a id='RasterIndex'></a>  <a href=\"#Raster Elements\"><code>Raster Elements:</code></a>\n",
    "\n",
    "<dl class=\"dl-horizontal\">\n",
    "  <dt><a href=\"#Raster\"><code>Raster</code></a></dt><dd>The base class of all rasters containing two-dimensional arrays. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#QuadMesh\"><code>QuadMesh</code></a></dt><dd>Raster type specifying 2D bins with two-dimensional array of values. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#HeatMap\"><code>HeatMap</code></a></dt><dd>Raster displaying sparse, discontinuous data collected in a two-dimensional space. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Image\"><code>Image</code></a></dt><dd>Raster containing a two-dimensional array covering a continuous space (sliceable). <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#RGB\"><code>RGB</code></a></dt><dd>Image with 3 (R,G,B) or 4 (R,G,B,Alpha) color channels. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#HSV\"><code>HSV</code></a></dt><dd>Image with 3 (Hue, Saturation, Value) or 4 channels. <font color='green'>&#x2713;</font></dd>\n",
    "</dl>\n",
    "\n",
    "\n",
    "### <a id='TabularIndex'></a> <a href=\"#Tabular Elements\"><code>Tabular Elements:</code></a>\n",
    "\n",
    "\n",
    "<dl class=\"dl-horizontal\">\n",
    "  <dt><a href=\"#ItemTable\"><code>ItemTable</code></a></dt><dd>Ordered collection of key-value pairs (ordered dictionary). <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Table\"><code>Table</code></a></dt><dd>Collection of arbitrary data with arbitrary key and value dimensions. <font color='green'>&#x2713;</font></dd>\n",
    "  </dl>\n",
    "  \n",
    "### <a id='AnnotationIndex'></a>  <a href=\"#Annotation Elements\"><code>Annotations:</code></a>\n",
    "\n",
    "  \n",
    " <dl class=\"dl-horizontal\">\n",
    "  <dt><a href=\"#VLine\"><code>VLine</code></a></dt><dd>Vertical line annotation. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#HLine\"><code>HLine</code></a></dt><dd>Horizontal line annotation. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Spline\"><code>Spline</code></a></dt><dd>Bezier spline (arbitrary curves). <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Text\"><code>Text</code></a></dt><dd>Text annotation on an <code>Element</code>. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Arrow\"><code>Arrow</code></a></dt><dd>Arrow on an <code>Element</code> with optional text label. <font color='red'>&#x2717;</font></dd>\n",
    "</dl>\n",
    "\n",
    "\n",
    "### <a id='PathIndex'></a>  <a href=\"#Path Elements\"><code>Paths:</code></a>\n",
    "\n",
    "<dl class=\"dl-horizontal\">\n",
    "  <dt><a href=\"#Path\"><code>Path</code></a></dt><dd>Collection of paths. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Contours\"><code>Contours</code></a></dt><dd>Collection of paths, each with an associated value. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Polygons\"><code>Polygons</code></a></dt><dd>Collection of filled, closed paths with an associated value. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Bounds\"><code>Bounds</code></a></dt><dd>Box specified by corner positions. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Box\"><code>Box</code></a></dt><dd>Box specified by center position, radius, and aspect ratio. <font color='green'>&#x2713;</font></dd>\n",
    "  <dt><a href=\"#Ellipse\"><code>Ellipse</code></a></dt><dd>Ellipse specified by center position, radius, and aspect ratio. <font color='green'>&#x2713;</font></dd>\n",
    "</dl>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ``Element`` <a id='Element'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**The basic or fundamental types of data that can be visualized.**\n",
    "\n",
    "``Element`` is the base class for all the other HoloViews objects shown in this section.\n",
    "\n",
    "All ``Element`` objects accept ``data`` as the first argument to define the contents of that element. In addition to its implicit type, each element object has a ``group`` string defining its category, and a ``label`` naming this particular item, as described in the [Introduction](Introduction.ipynb#value).\n",
    "\n",
    "When rich display is off, or if no visualization has been defined for that type of ``Element``, the ``Element`` is presented with a default textual representation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import holoviews as hv\n",
    "hv.notebook_extension(bokeh=True)\n",
    "hv.Element(None, group='Value', label='Label')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In addition, ``Element`` has key dimensions (``kdims``), value dimensions (``vdims``), and constant dimensions (``cdims``) to describe the semantics of indexing within the ``Element``, the semantics of the underlying data contained by the ``Element``, and any constant parameters associated with the object, respectively.\n",
    "Dimensions are described in the [Introduction](Introduction.ipynb).\n",
    "\n",
    "The remaining ``Element`` types each have a rich, graphical display as shown below."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ``Chart`` Elements <a id='Chart Elements'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Visualization of a dependent variable against an independent variable**\n",
    "\n",
    "The first large class of ``Elements`` is the ``Chart`` elements. These objects have at least one fully indexable, sliceable key dimension (typically the *x* axis in a plot), and usually have one or more value dimension(s) (often the *y* axis) that may or may not be indexable depending on the implementation.  The key dimensions are normally the parameter settings for which things are measured, and the value dimensions are the data points recorded at those settings.  \n",
    "\n",
    "As described in the [Columnar Data tutorial](Columnar_Data.ipynb), the data can be stored in several different internal formats, such as a NumPy array of shape (N, D), where N is the number of samples and D the number of dimensions. A somewhat larger list of formats can be accepted, including any of the supported internal formats, or\n",
    "\n",
    "1. As a list of length N containing tuples of length D.\n",
    "2. As a tuple of length D containing iterables of length N."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``Curve`` <a id='Curve'></a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "points = [(0.1*i, np.sin(0.1*i)) for i in range(100)]\n",
    "hv.Curve(points)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A ``Curve`` is a set of values provided for some set of keys from a [continuously indexable 1D coordinate system](Continuous_Coordinates.ipynb), where the plotted values will be connected up because they are assumed to be samples from a continuous relation."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``ErrorBars`` <a id='ErrorBars'></a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(7)\n",
    "points = [(0.1*i, np.sin(0.1*i)) for i in range(100)]\n",
    "errors = [(0.1*i, np.sin(0.1*i), np.random.rand()/2) for i in np.linspace(0, 100, 11)]\n",
    "hv.Curve(points) * hv.ErrorBars(errors)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "``ErrorBars`` is a set of x-/y-coordinates with associated error values.  Error values may be either symmetric or asymmetric, and thus can be supplied as an Nx3 or Nx4 array (or any of the alternative constructors Chart Elements allow)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts ErrorBars\n",
    "points = [(0.1*i, np.sin(0.1*i)) for i in range(100)]\n",
    "errors = [(0.1*i, np.sin(0.1*i), np.random.rand()/2, np.random.rand()/4) for i in np.linspace(0, 100, 11)]\n",
    "hv.Curve(points) * hv.ErrorBars(errors, vdims=['y', 'yerrneg', 'yerrpos'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``Area`` <a id='Area'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** *Area under the curve* **\n",
    "\n",
    "By default the Area Element draws just the area under the curve, i.e. the region between the curve and the origin."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xs = np.linspace(0, np.pi*4, 40)\n",
    "hv.Area((xs, np.sin(xs)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** * Area between curves * **\n",
    "\n",
    "When supplied a second value dimension the area is defined as the area between two curves."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X  = np.linspace(0,3,200)\n",
    "Y = X**2 + 3\n",
    "Y2 = np.exp(X) + 2\n",
    "Y3 = np.cos(X)\n",
    "hv.Area((X, Y, Y2), vdims=['y', 'y2']) * hv.Area((X, Y, Y3), vdims=['y', 'y3'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Stacked areas\n",
    "\n",
    "Areas are also useful to visualize multiple variables changing over time, but in order to be able to compare them the areas need to be stacked. Therefore the ``operation`` module provides the ``stack_area`` operation which makes it trivial to stack multiple Area in an (Nd)Overlay.\n",
    "\n",
    "In this example we will generate a set of 5 arrays representing percentages and create an Overlay of them. Then we simply call the ``stack_area`` operation on the Overlay to get a stacked area chart."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "values = np.random.rand(5, 20)\n",
    "percentages = (values/values.sum(axis=0)).T*100\n",
    "\n",
    "overlay = hv.Overlay([hv.Area(percentages[:, i], vdims=[hv.Dimension('value', unit='%')]) for i in range(5)])\n",
    "overlay + hv.Area.stack(overlay)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``Spread`` <a id='Spread'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "``Spread`` elements have the same data format as the ``ErrorBars`` element, namely x- and y-values with associated symmetric or asymmetric errors, but are interpreted as samples from a continuous distribution (just as ``Curve`` is the continuous version of ``Scatter``).  These are often paired with an overlaid ``Curve`` to show both the mean (as a curve) and the spread of values; see the [Columnar Data tutorial](Columnar_Data.ipynb) for examples. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Symmetric"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(42)\n",
    "xs = np.linspace(0, np.pi*2, 20)\n",
    "err = 0.2+np.random.rand(len(xs))\n",
    "hv.Spread((xs, np.sin(xs), err))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Asymmetric"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Spread (fill_color='indianred' fill_alpha=1)\n",
    "xs = np.linspace(0, np.pi*2, 20)\n",
    "hv.Spread((xs, np.sin(xs), 0.1+np.random.rand(len(xs)), 0.1+np.random.rand(len(xs))),\n",
    "          vdims=['y', 'yerrneg', 'yerrpos'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``Bars`` <a id='Bars'></a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = [('one',8),('two', 10), ('three', 16), ('four', 8), ('five', 4), ('six', 1)]\n",
    "bars = hv.Bars(data, kdims=[hv.Dimension('Car occupants', values='initial')], vdims=['Count'])\n",
    "bars + bars[['one', 'two', 'three']]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "``Bars`` is an ``NdElement`` type, so by default it is sorted. To preserve the initial ordering specify the ``Dimension`` with values set to 'initial', or you can supply an explicit list of valid dimension keys.\n",
    "\n",
    "``Bars`` support up to two key dimensions which can be laid by ``'group'`` and ``'stack'`` dimensions. By default the key dimensions are mapped onto the first, second ``Dimension`` of the ``Bars`` object, but this behavior can be overridden via the ``group_index`` and ``stack_index`` options."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Bars [group_index=0 stack_index=1]\n",
    "from itertools import product\n",
    "np.random.seed(3)\n",
    "groups, stacks = ['A', 'B'], ['a', 'b']\n",
    "keys = product(groups, stacks)\n",
    "hv.Bars([k+(np.random.rand()*100.,) for k in keys],\n",
    "         kdims=['Group', 'Stack'], vdims=['Count'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``BoxWhisker`` <a id='BoxWhisker'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``BoxWhisker`` Element allows representing distributions of data varying by 0-N key dimensions. To represent the distribution of a single variable, we can create a BoxWhisker Element with no key dimensions and a single value dimension:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hv.BoxWhisker(np.random.randn(200), kdims=[], vdims=['Value'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "BoxWhisker Elements support any number of dimensions and may also be rotated. To style the boxes and whiskers, supply ``boxprops``, ``whiskerprops``, and ``flierprops``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts BoxWhisker [invert_axes=True width=600]\n",
    "groups = [chr(65+g) for g in np.random.randint(0, 3, 200)]\n",
    "hv.BoxWhisker((groups, np.random.randint(0, 5, 200), np.random.randn(200)),\n",
    "              kdims=['Group', 'Category'], vdims=['Value']).sort()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``Histogram`` <a id='Histogram'></a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(1)\n",
    "data = [np.random.normal() for i in range(10000)]\n",
    "frequencies, edges = np.histogram(data, 20)\n",
    "hv.Histogram(frequencies, edges)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "``Histogram``s partition the `x` axis into discrete (but not necessarily regular) bins, showing counts in each as a bar.\n",
    "\n",
    "Almost all Element types, including ``Histogram``, may be projected onto a polar axis by supplying ``projection='polar'`` as a plot option."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Histogram [projection='polar' show_grid=True]\n",
    "data = [np.random.rand()*np.pi*2 for i in range(100)]\n",
    "frequencies, edges = np.histogram(data, 20)\n",
    "hv.Histogram(frequencies, edges, kdims=['Angle'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``Scatter`` <a id='Scatter'></a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Scatter (color='k', marker='s', s=10)\n",
    "np.random.seed(42)\n",
    "points = [(i, np.random.random()) for i in range(20)]\n",
    "hv.Scatter(points) + hv.Scatter(points)[12:20]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Scatter is the discrete equivalent of Curve, showing *y* values for discrete *x* values selected.  See [``Points``](#Points) for more information.\n",
    "\n",
    "The marker shape specified above can be any supported by [matplotlib](http://matplotlib.org/api/markers_api.html), e.g. ``s``, ``d``, or ``o``; the other options select the color and size of the marker.  For convenience with the [bokeh backend](Bokeh_Backend), the matplotlib marker options are supported using a compatibility function in HoloViews."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``Points`` <a id='Points'></a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(12)\n",
    "points = np.random.rand(50,2)\n",
    "hv.Points(points) + hv.Points(points)[0.6:0.8,0.2:0.5]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see, ``Points`` is very similar to ``Scatter``, and can produce some plots that look identical.  However, the two ``Element``s are very different semantically.  For ``Scatter``, the dots each show a dependent variable *y* for some *x*, such as in the ``Scatter`` example above where we selected regularly spaced values of *x* and then created a random number as the corresponding *y*.  I.e., for ``Scatter``, the *y* values are the data; the *x*s are just where the data values are located. For ``Points``, both *x* and *y* are independent variables, known as ``key_dimensions`` in HoloViews:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for o in [hv.Points(points,name=\"Points \"), hv.Scatter(points,name=\"Scatter\")]:\n",
    "    for d in ['key','value']:\n",
    "        print(\"%s %s_dimensions: %s \" % (o.name, d, o.dimensions(d,label=True)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``Scatter`` object expresses a dependent relationship between *x* and *y*, making it useful for combining with other similar ``Chart`` types, while the ``Points`` object expresses the relationship of two independent keys *x* and *y* with optional ``vdims`` (zero in this case), which makes ``Points`` objects meaningful to combine with the ``Raster`` types below.\n",
    "\n",
    "Of course, the ``vdims`` need not be empty for ``Points``; here is an example with two additional quantities for each point, as ``value_dimension``s *z* and &alpha; visualized as the color and size of the dots, respectively:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Points [color_index=2 size_index=3 scaling_factor=50]\n",
    "np.random.seed(10)\n",
    "data = np.random.rand(100,4)\n",
    "\n",
    "points = hv.Points(data, vdims=['z', 'alpha'])\n",
    "points + points[0.3:0.7, 0.3:0.7].hist()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Such a plot wouldn't be meaningful for ``Scatter``, but is a valid use for ``Points``, where the *x* and *y* locations are independent variables representing coordinates, and the \"data\" is conveyed by the size and color of the dots.\n",
    "\n",
    "### ``Spikes`` <a id='Spikes'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Spikes represent any number of horizontal or vertical line segments with fixed or variable heights. There are a number of disparate uses for this type.  First of all, they may be used as a rugplot to give an overview of a one-dimensional distribution. They may also be useful in more domain-specific cases, such as visualizing spike trains for neurophysiology or spectrograms in physics and chemistry applications.\n",
    "\n",
    "In the simplest case, a Spikes object represents coordinates in a 1D distribution:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Spikes (line_alpha=0.4) [spike_length=0.1]\n",
    "xs = np.random.rand(50)\n",
    "ys = np.random.rand(50)\n",
    "hv.Points((xs, ys)) * hv.Spikes(xs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When supplying two dimensions to the Spikes object, the second dimension will be mapped onto the line height. Optionally, you may also supply a cmap and color_index to map color onto one of the dimensions. This way we can, for example, plot a mass spectrogram:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Spikes (cmap='Reds')\n",
    "hv.Spikes(np.random.rand(20, 2), kdims=['Mass'], vdims=['Intensity'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Another possibility is to draw a number of spike trains as you would encounter in neuroscience. Here we generate 10 separate random spike trains and distribute them evenly across the space by setting their ``position``. By also declaring some ``yticks``, each spike train can be labeled individually:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Spikes [spike_length=0.1] NdOverlay [show_legend=False]\n",
    "hv.NdOverlay({i: hv.Spikes(np.random.randint(0, 100, 10), kdims=['Time']).opts(plot=dict(position=0.1*i))\n",
    "              for i in range(10)}).opts(plot=dict(yticks=[((i+1)*0.1-0.05, i) for i in range(10)]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we may use ``Spikes`` to visualize marginal distributions as adjoined plots using the ``<<`` adjoin operator:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Spikes (line_alpha=0.2)\n",
    "points = hv.Points(np.random.randn(500, 2))\n",
    "points << hv.Spikes(points['y']) << hv.Spikes(points['x'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``VectorField`` <a id='VectorField'></a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts VectorField [size_index=3]\n",
    "x,y  = np.mgrid[-10:10,-10:10] * 0.25\n",
    "sine_rings  = np.sin(x**2+y**2)*np.pi+np.pi\n",
    "exp_falloff = 1/np.exp((x**2+y**2)/8)\n",
    "\n",
    "vector_data = [x,y,sine_rings, exp_falloff]\n",
    "hv.VectorField(vector_data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see above, here the *x* and *y* positions are chosen to make a regular grid. The arrow angles follow a sinsoidal ring pattern, and the arrow lengths fall off exponentially from the center, so this plot has four dimensions of data (direction and length for each *x,y* position).\n",
    "\n",
    "Using the IPython ``%%opts`` cell-magic (described in the [Options tutorial](Options), along with the Python equivalent), we can also use color as a redundant indicator to the direction or magnitude:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts VectorField [size_index=3] VectorField.A [color_index=2] VectorField.M [color_index=3]\n",
    "hv.VectorField(vector_data, group='A') + hv.VectorField(vector_data, group='M')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``SideHistogram`` <a id='SideHistogram'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``.hist`` method conveniently adjoins a histogram to the side of any ``Chart``, ``Surface``, or ``Raster`` component, as well as many of the container types (though it would be reporting data from one of these underlying ``Element`` types).  For a ``Raster`` using color or grayscale to show values (see ``Raster`` section below), the side histogram doubles as a color bar or key."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "np.random.seed(42)\n",
    "points = [(i, np.random.normal()) for i in range(800)]\n",
    "hv.Scatter(points).hist()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ``Chart3D`` Elements <a id='Chart3D Elements'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``Surface`` <a id='Surface'></a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Surface (cmap='jet' rstride=20, cstride=2)\n",
    "hv.Surface(np.sin(np.linspace(0,100*np.pi*2,10000)).reshape(100,100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Surface is used for a set of gridded points whose associated value dimension represents samples from a continuous surface; it is the equivalent of a ``Curve`` but with two key dimensions instead of just one."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``Scatter3D`` <a id='Scatter3D'></a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Scatter3D [azimuth=40 elevation=20]\n",
    "x,y = np.mgrid[-5:5, -5:5] * 0.1\n",
    "heights = np.sin(x**2+y**2)\n",
    "hv.Scatter3D(zip(x.flat,y.flat,heights.flat))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "``Scatter3D`` is the equivalent of ``Scatter`` but for two key dimensions, rather than just one.\n",
    "\n",
    "\n",
    "### ``Trisurface`` <a id='Trisurface'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``Trisurface`` Element renders any collection of 3D points as a Surface by applying Delaunay triangulation.  It thus supports arbitrary, non-gridded data, but it does not support indexing to find data values, since finding the closest ones would require a search."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Trisurface [fig_size=200] (cmap='hot_r')\n",
    "hv.Trisurface((x.flat,y.flat,heights.flat))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ``Raster`` Elements <a id='Raster Elements'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**A collection of raster image types**\n",
    "\n",
    "The second large class of ``Elements`` is the raster elements. Like ``Points`` and unlike the other  ``Chart`` elements, ``Raster Elements`` live in a 2D key-dimensions space. For the ``Image``, ``RGB``, and ``HSV`` elements, the coordinates of this two-dimensional key space are defined in a [continuously indexable coordinate system](Continuous_Coordinates.ipynb)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``Raster`` <a id='Raster'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A ``Raster`` is the base class for image-like ``Elements``, but may be used directly to visualize 2D arrays using a color map. The coordinate system of a ``Raster`` is the raw indexes of the underlying array, with integer values always starting from (0,0) in the top left, with default extents corresponding to the shape of the array.  The ``Image`` subclass visualizes similarly, but using a continuous Cartesian coordinate system suitable for an array that represents some underlying continuous region."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x,y = np.mgrid[-50:51, -50:51] * 0.1\n",
    "hv.Raster(np.sin(x**2+y**2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``QuadMesh`` <a id='QuadMesh'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The basic ``QuadMesh`` is a 2D grid of bins specified as x-/y-values specifying a regular sampling or edges, with arbitrary sampling and an associated 2D array containing the bin values. The coordinate system of a ``QuadMesh`` is defined by the bin edges, therefore any index falling into a binned region will return the appropriate value. Unlike ``Image`` objects, slices must be inclusive of the bin edges."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "n = 21\n",
    "xs = np.logspace(1, 3, n)\n",
    "ys = np.linspace(1, 10, n)\n",
    "hv.QuadMesh((xs, ys, np.random.rand(n-1, n-1)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "QuadMesh may also be used to represent an arbitrary mesh of quadrilaterals by supplying three separate 2D arrays representing the coordinates of each quadrilateral in a 2D space. Note that when using ``QuadMesh`` in this mode, slicing and indexing semantics and most operations will currently not work."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "coords = np.linspace(-1.5,1.5,n)\n",
    "X,Y = np.meshgrid(coords, coords);\n",
    "Qx = np.cos(Y) - np.cos(X)\n",
    "Qz = np.sin(Y) + np.sin(X)\n",
    "Z = np.sqrt(X**2 + Y**2)\n",
    "hv.QuadMesh((Qx, Qz, Z))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``HeatMap`` <a id='HeatMap'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A ``HeatMap`` displays like a typical raster image, but the input is a dictionary indexed with two-dimensional keys, not a Numpy array or Pandas dataframe. As many rows and columns as required will be created to display the values in an appropriate grid format.  Values unspecified are left blank, and the keys can be any Python datatype (not necessarily numeric).  One typical usage is to show values from a set of experiments, such as a parameter space exploration, and many other such visualizations are shown in the [Containers](Containers.ipynb) and [Exploring Data](Exploring_Data.ipynb) tutorials. Each value in a ``HeatMap`` is labeled explicitly by default, and so this component is not meant for very large numbers of samples.  With the default color map, high values (in the upper half of the range present) are colored orange and red, while low values (in the lower half of the range present) are colored shades of blue."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = {(chr(65+i),chr(97+j)): i*j for i in range(5) for j in range(5) if i!=j}\n",
    "hv.HeatMap(data).sort()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``Image`` <a id='Image'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Like ``Raster``, a HoloViews ``Image`` allows you to view 2D arrays using an arbitrary color map. Unlike ``Raster``, an ``Image`` is associated with a [2D coordinate system in continuous space](Continuous_Coordinates.ipynb), which is appropriate for values sampled from some underlying continuous distribution (as in a photograph or other measurements from locations in real space).  Slicing, sampling, etc. on an ``Image`` all use this continuous space, whereas the corresponding operations on a ``Raster`` work on the raw array coordinates."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x,y = np.mgrid[-50:51, -50:51] * 0.1\n",
    "bounds=(-1,-1,1,1)   # Coordinate system: (left, bottom, top, right)\n",
    "\n",
    "(hv.Image(np.sin(x**2+y**2),   bounds=bounds) \n",
    " + hv.Image(np.sin(x**2+y**2), bounds=bounds)[-0.5:0.5, -0.5:0.5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Notice how, because our declared coordinate system is continuous, we can slice with any floating-point value we choose. The appropriate range of the samples in the input numpy array will always be displayed, whether or not there are samples at those specific floating-point values.\n",
    "\n",
    "It is also worth noting that the name ``Image`` can clash with other common libraries, which is one reason to avoid unqualified imports like ``from holoviews import *``. For instance, the Python Imaging Libray provides an ``Image`` module, and IPython itself supplies an ``Image`` class in ``IPython.display``.  Python namespaces allow you to avoid such problems, e.g. using ``from PIL import Image as PILImage`` or using ``import holoviews as hv`` and then ``hv.Image()``, as we do in these tutorials."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``RGB`` <a id='RGB'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``RGB`` element is an ``Image`` that supports red, green, blue channels:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x,y = np.mgrid[-50:51, -50:51] * 0.1\n",
    "\n",
    "r = 0.5*np.sin(np.pi  +3*x**2+y**2)+0.5\n",
    "g = 0.5*np.sin(x**2+2*y**2)+0.5\n",
    "b = 0.5*np.sin(np.pi/2+x**2+y**2)+0.5\n",
    "\n",
    "hv.RGB(np.dstack([r,g,b]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can see how the RGB object is created from the original channels:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Image (cmap='gray')\n",
    "hv.Image(r,label=\"R\") + hv.Image(g,label=\"G\") + hv.Image(b,label=\"B\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "``RGB`` also supports an optional alpha channel, which will be used as a mask revealing or hiding any ``Element``s it is overlaid on top of:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Image (cmap='gray')\n",
    "mask = 0.5*np.sin(0.2*(x**2+y**2))+0.5\n",
    "rgba = hv.RGB(np.dstack([r,g,b,mask]))\n",
    "\n",
    "bg = hv.Image(0.5*np.cos(x*3)+0.5, label=\"Background\") * hv.VLine(x=0,label=\"Background\")\n",
    "\n",
    "overlay = bg*rgba\n",
    "overlay.label=\"RGBA Overlay\"\n",
    "\n",
    "bg + hv.Image(mask,label=\"Mask\") + overlay"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``HSV`` <a id='HSV'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "HoloViews makes it trivial to  work in any color space that can be converted to ``RGB`` by making a simple subclass of ``RGB`` as appropriate. For instance, we also provide the  HSV (hue, saturation, value) color space, which is useful for plotting cyclic data (as the Hue) along with two additional dimensions (controlling the saturation and value of the color, respectively):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x,y = np.mgrid[-50:51, -50:51] * 0.1\n",
    "h = 0.5 + np.sin(0.2*(x**2+y**2)) / 2.0\n",
    "s = 0.5*np.cos(y*3)+0.5\n",
    "v = 0.5*np.cos(x*3)+0.5\n",
    "\n",
    "hsv = hv.HSV(np.dstack([h, s, v]))\n",
    "hsv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can see how this is created from the original channels:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Image (cmap='gray')\n",
    "hv.Image(h, label=\"H\") + hv.Image(s, label=\"S\") + hv.Image(v, label=\"V\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# ``Tabular`` Elements <a id='Tabular Elements'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**General data structures for holding arbitrary information**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ``ItemTable`` <a id='ItemTable'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An ``ItemTable`` is an ordered collection of key, value pairs. It can be used to directly visualize items in a tabular format where the items may be supplied as an ``OrderedDict`` or a list of (key,value) pairs. A standard Python dictionary can be easily visualized using a call to the ``.items()`` method, though the entries in such a dictionary are not kept in any particular order, and so you may wish to sort them before display.  One typical usage for an ``ItemTable`` is to list parameter values or measurements associated with an adjacent ``Element``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hv.ItemTable([('Age', 10), ('Weight',15), ('Height','0.8 meters')])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ``Table`` <a id='Table'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A table is more general than an ``ItemTable``, as it allows multi-dimensional keys and multidimensional values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "keys =   [('M',10), ('M',16), ('F',12)]\n",
    "values = [(15, 0.8), (18, 0.6), (10, 0.8)]\n",
    "table = hv.Table(zip(keys,values), \n",
    "                 kdims = ['Gender', 'Age'], \n",
    "                 vdims=['Weight', 'Height'])\n",
    "table"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that you can use select using tables, and once you select using a full, multidimensional key, you get an ``ItemTable`` (shown on the right):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "table.select(Gender='M') + table.select(Gender='M', Age=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``Table`` is used as a common data structure that may be converted to any other HoloViews data structure using the ``TableConversion`` class.\n",
    "\n",
    "The functionality of the ``TableConversion`` class may be conveniently accessed using the ``.to`` property. For more extended usage of table conversion see the [Columnar Data](Columnnar_Data.ipynb) and [Pandas Conversion](Pandas_Conversion.ipynb) Tutorials."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "table.select(Gender='M').to.curve(kdims=[\"Age\"], vdims=[\"Weight\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# ``Annotation`` Elements <a id='Annotation Elements'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Useful information that can be overlaid onto other components**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Annotations are components designed to be overlaid on top of other ``Element`` objects. To demonstrate annotation and paths, we will be drawing many of our elements on top of an RGB Image:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scene = hv.RGB.load_image('../assets/penguins.png')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``VLine`` and ``HLine``  <a id='VLine'></a><a id='HLine'></a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scene * hv.VLine(-0.05) + scene * hv.HLine(-0.05)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``Spline``  <a id='Spline'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``Spline`` annotation is used to draw Bezier splines using the same semantics as [matplotlib splines](http://matplotlib.org/api/path_api.html). In the overlay below, the spline is in dark blue and the control points are in light blue."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "points = [(-0.3, -0.3), (0,0), (0.25, -0.25), (0.3, 0.3)]\n",
    "codes = [1,4,4,4]\n",
    "scene * hv.Spline((points,codes)) * hv.Curve(points)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Text and Arrow  <a id='Text'></a><a id='Arrow'></a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scene * hv.Text(0, 0.2, 'Adult\\npenguins') + scene * hv.Arrow(0,-0.1, 'Baby penguin', 'v')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Paths  <a id='Path Elements'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Line-based components that can be overlaid onto other components**\n",
    "\n",
    "Paths are a subclass of annotations that involve drawing line-based components on top of other elements. Internally, Path Element types hold a list of Nx2 arrays, specifying the x/y-coordinates along each path. The data may be supplied in a number of ways, including:\n",
    "\n",
    "1. A list of Nx2 numpy arrays.\n",
    "2. A list of lists containing x/y coordinate tuples.\n",
    "3. A tuple containing an array of length N with the x-values and a second array of shape NxP, where P is the number of paths.\n",
    "4. A list of tuples each containing separate x and y values."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ``Path``  <a id='Path'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A ``Path`` object is actually a collection of paths which can be arbitrarily specified. Although there may be multiple unconnected paths in a single ``Path`` object, they will all share the same style. Only by overlaying multiple ``Path`` objects do you iterate through the defined color cycle (or any other style options that have been defined)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "angle = np.linspace(0, 2*np.pi, 100)\n",
    "baby = list(zip(0.15*np.sin(angle),  0.2*np.cos(angle)-0.2))\n",
    "\n",
    "adultR = [(0.25, 0.45), (0.35,0.35), (0.25, 0.25), (0.15, 0.35), (0.25, 0.45)]\n",
    "adultL = [(-0.3, 0.4), (-0.3, 0.3), (-0.2, 0.3), (-0.2, 0.4),(-0.3, 0.4)]\n",
    "\n",
    "scene * hv.Path([adultL, adultR, baby]) * hv.Path([baby])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ``Contours``  <a id='Contours'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A ``Contours`` object is similar to ``Path`` object except each of the path elements is associated with a numeric value, called the ``level``. Sadly, our penguins are too complicated to give a simple example so instead we will simply mark the first couple of rings of our earlier ring pattern:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x,y = np.mgrid[-50:51, -50:51] * 0.1\n",
    "\n",
    "def circle(radius, x=0, y=0):\n",
    "    angles = np.linspace(0, 2*np.pi, 100)\n",
    "    return np.array( list(zip(x+radius*np.sin(angles), y+radius*np.cos(angles))))\n",
    "\n",
    "hv.Image(np.sin(x**2+y**2)) * hv.Contours([circle(0.22)], level=0) * hv.Contours([circle(0.33)], level=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ``Polygons`` <a id='Polygons'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A ``Polygons`` object is similar to a ``Contours`` object except that each supplied path is closed and filled. Just like ``Contours``, optionally a ``level`` may be supplied; the Polygons will then be colored according to the supplied ``cmap``. Non-finite values such as ``np.NaN`` or ``np.inf`` will default to the supplied ``facecolor``.\n",
    "\n",
    "Polygons with values can be used to build heatmaps with arbitrary shapes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%opts Polygons (cmap='hot' line_color='black' line_width=2)\n",
    "np.random.seed(35)\n",
    "hv.Polygons([np.random.rand(4,2)], level=0.5) *\\\n",
    "hv.Polygons([np.random.rand(4,2)], level=1.0) *\\\n",
    "hv.Polygons([np.random.rand(4,2)], level=1.5) *\\\n",
    "hv.Polygons([np.random.rand(4,2)], level=2.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Polygons without a value are useful as annotation, but also allow us to draw arbitrary shapes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def rectangle(x=0, y=0, width=1, height=1):\n",
    "    return np.array([(x,y), (x+width, y), (x+width, y+height), (x, y+height)])\n",
    "\n",
    "(hv.Polygons([rectangle(width=2), rectangle(x=6, width=2)]).opts(style={'fill_color': '#a50d0d'})\n",
    "* hv.Polygons([rectangle(x=2, height=2), rectangle(x=5, height=2)]).opts(style={'fill_color': '#ffcc00'})\n",
    "* hv.Polygons([rectangle(x=3, height=2, width=2)]).opts(style={'fill_color': 'cyan'}))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ``Bounds``  <a id='Bounds'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A bounds is a rectangular area specified as a tuple in  ``(left, bottom, right, top)`` format. It is useful for denoting a region of interest defined by some bounds, whereas ``Box`` (below) is useful for drawing a box at a specific location."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scene * hv.Bounds(0.2) * hv.Bounds((0.2, 0.2, 0.45, 0.45,))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ``Box`` <a id='Box'></a> and ``Ellipse`` <a id='Ellipse'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A ``Box`` is similar to a ``Bounds`` except you specify the box position, width, and aspect ratio instead of the coordinates of the box corners.  An ``Ellipse`` is specified just as for ``Box``, but has a rounded shape."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scene * hv.Box(    -0.25, 0.3, 0.3, aspect=0.5) * hv.Box(    0, -0.2, 0.1) + \\\n",
    "scene * hv.Ellipse(-0.25, 0.3, 0.3, aspect=0.5) * hv.Ellipse(0, -0.2, 0.1)"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
